/**
 * 链表
 * created by gw 2018/5/29
 */
import Node from "./node";
export default class LinkedList {
    constructor() {
        this.head = null;
        this.length = 0;
    }

    /**
     * 往链表末尾添加元素
     * @param {*} element 
     */
    push(element) {
        let node = new Node(element);
        if (this.head) {
            let current = this.head;
            while (current.next) {
                current = current.next;
            }
            current.next = node;
        } else {
            //头部为null就添加为头部
            this.head = node;
        }
        this.length++;
    }

    /**
     * 在链表任意位置插入元素
     * @param {*} position 
     * @param {*} element 
     */
    insert(position, element) {
        let node = new Node(element);
        let index = 0, previous = this.head;
        if (position !== 0) {
            //先找到要插入位置的前一个元素previous
            while (index++ < position - 1) {
                previous = previous.next;
            }
            // previous  = this.getElement(position - 1);
            node.next = previous.next;
            previous.next = node;
        } else {
            node.next = this.head;
            this.head = node;
        }
        this.length++;
    }

    /**
     * 获取元素对应下标
     * @param {*} element 
     */
    indexOf(element) {
        let index = 0, current = this.head;
        while (current) {
            if (element === current.element) {
                return index;
            }
            index++;
            current = current.next;
        }
        return -1;
    }

    //根据下标获取元素值
    getElement(position) {
        let index = 0, current = this.head;
        if (position !== 0) {
            while(index++ < position) {
                current = current.next;
            }
            return current.element; 
        } else {
            return this.head.element;
        }
    }

    /**
     * 根据position删除元素
     * @param {*} position 
     */
    removeAt(position) {
        let index = 0, current = this.head, previous;
        if (position !== 0) {
            //这里会先执行<判断，再取++
            //先找到要删除的元素
            while(index++ < position) {
                previous = current;
                current = current.next;
            }
            previous.next = current.next;
            
        } else {
            this.head = current.next;
        }
        this.length--;
        return current.element;
    }

    /**
     * 删除某个元素
     * @param {*} element 
     */
    remove(element) {
        let position = this.indexOf(element);
        return this.removeAt(position);
    }

    /**
     * 
     * @param {Number, Object} arg1 
     * @param {Number, Object} arg2 
     */
    swap(arg1, arg2) {
        //根据索引位置进行交换
        if (typeof arg1 === "number") {
            if (this.length - 1 < arg1 || this.length - 1 < arg2)
                return false;
            let el1 = this.getElement(arg1);
            let el2 = this.getElement(arg2);
            this.replace(arg1, el2); 
            this.replace(arg2, el1);
        }
    }
    
    /**
     * 对某个元素进行替换
     * @param {*} position 
     * @param {*} element 
     */
    replace(position, element) {
        let node = new Node(element);
        //current: 要被替换的元素
        let current = this.head, previous;
        let i = 0;
        //如果该链表为空，则直接赋值给头部
        if (!current) {
            this.head = node;
            return true;
        }
        //替换头部
        if (position === 0) {
            this.head = node;
            node.next = current.next;
            return true;
        }
        //找到要被替换元素的前一个元素
        while (i++ < position) {
            previous = current;
            current = previous.next;
        }
        node.next = current.next;
        previous.next = node;
        return true;
    }

    /**
     * 将链表转为字符串输出
     */
    toString() {
        let string = "", current = this.head;
        while(current) {
            string += current.element + (current.next ? "," : "");
            current = current.next;
        }
        return string
    }

    /**
     * 是否为空链表
     */
    isEmpty() {
        return this.length === 0;
    }

    /**
     * 获取链表头部元素
     */
    getHead() {
        return this.head;
    }
}